﻿using SqlScriptVault.Commands;
using SqlScriptVault.Model;
using SqlScriptVault.Properties;
using SqlScriptVault.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SqlScriptVault.ViewModel
{
    class ExecutionViewModel : BaseNotifyViewModel
    {
        private readonly IFileService _fileService;
        private readonly IMessageDisplayService _messageDisplayService;

        private ScriptVault _scriptVault;

        private const string ConnectionVaultFileName = "ConnectionVault.dat";

        public ExecutionViewModel()
            : this(new FileService(), new MessageDisplayService())
        {
        }

        public ExecutionViewModel(IFileService fileService, IMessageDisplayService messageDisplayService)
        {
            _fileService = fileService;
            _messageDisplayService = messageDisplayService;

            ServerTypes = new List<ServerTypeChecker>(from serverType in new Settings().ServerTypes.Split('|') select new ServerTypeChecker { Checked = false, Text = serverType });

            if (_fileService.Exists(ConnectionVaultFileName))
            {
                ConnectionVault = _fileService.LoadFile<ConnectionVault>(ConnectionVaultFileName);
            }
        }

        public event Action RequestClose;

        public Script CurrentScript { get; set; }
        public ConnectionVault ConnectionVault { get; private set; }
        public ServerGroup CurrentServerGroup { get; set; }
        public List<ServerTypeChecker> ServerTypes { get; private set; }

        public ScriptVault ScriptVault
        {
            get { return _scriptVault; }
            set
            {
                _scriptVault = value;

                RaisePropertyChanged("ScriptVault");
            }
        }

        public RelayCommand ExecuteCommand
        {
            get
            {
                return new RelayCommand(param => Execute());
            }
        }

        public void Execute()
        {
            if (CurrentServerGroup == null)
            {
                _messageDisplayService.ShowErrorMessage("Select a target database environment.");
                return;
            }

            var selectedServerTypes = (from serverType in ServerTypes
                                       where serverType.Checked
                                       select serverType.Text).ToList();

            if (selectedServerTypes.Count() == 0)
            {
                _messageDisplayService.ShowErrorMessage("Select at least one target server type.");
                return;
            }

            Dictionary<Server, SqlCredential> sqlCredentials = new Dictionary<Server, SqlCredential>();

            foreach (Server server in CurrentServerGroup.Servers)
            {
                if (!selectedServerTypes.Contains(server.ServerType))
                {
                    continue;
                }

                if (!server.WindowsAuthentication)
                {
                    SqlCredential sqlCredential = _messageDisplayService.ShowLoginWindow(server);

                    if (sqlCredential == null)
                    {
                        _messageDisplayService.ShowErrorMessage(string.Format("Please provide login details for {0}.", server.FullName));
                        return;
                    }

                    sqlCredentials.Add(server, sqlCredential);
                }
            }

            RequestClose();

            ScriptVaultExecution scriptVaultExecution = new ScriptVaultExecution(CurrentServerGroup, selectedServerTypes);
            DateTime dateTime = DateTime.Now;
            List<Script> requiredScripts;

            if (CurrentScript == null)
            {
                requiredScripts = ScriptVault.Scripts.ToList();
            }
            else
            {
                requiredScripts = ScriptVault.Scripts.Where(s => s.Number >= CurrentScript.Number).OrderBy(s => s.Number).ToList();
            }

            foreach (var script in requiredScripts)
            {
                if (script.ServerTypes.Any(st => selectedServerTypes.Contains(st)))
                {
                    scriptVaultExecution.AddScript(script);
                }
            }

            _messageDisplayService.OpenExecutionProgress(scriptVaultExecution, sqlCredentials);

            ScriptVault.AddExecution(dateTime, scriptVaultExecution);

            EventService.Instance.Publish(EventService.SaveEvent, null);
        }
    }
}
